package com.guochenglang.www.util.connect;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.LinkedList;

/**
 * 连接池类
 *
 * @author 郭程朗
 */
public class ConnectPool implements Connectutil {

    /**
     * 构造方法,创建对象时初始化连接池
     */
    public ConnectPool() {
        init(config);
    }

    /**
     * threadLocal
     */
    private static final ThreadLocal<Connection> THREAD_LOCAL = new ThreadLocal<>();

    /**
     * 当前链接个数
     */
    private static int connection = 0;
    /**
     * 配置文件对象生成
     */
    private static Config config = new Config();
    /**
     * 创建集合对象,初始化连接池（使用public是为了在test中打印集合）
     */
    private static LinkedList<Connection> arr = init(config);

    /**
     * 数据库链接的初始化的方法
     */
    private static LinkedList<Connection> init(Config config) {
        //获取初始连接个数
        int init = config.getInit();
        //创建集合
        LinkedList<Connection> arr = new LinkedList<>();
        while (init > 0) {
            //将集连接对象添加到集合中
            Connection conn = Jdbc.getConnection();
            arr.add(conn);
            init--;
        }
        return arr;
    }


    /**
     * 获取连接池链接的底层方法
     */
    public Connection getConnectionInner() throws SQLException {
        //从threadLocal获得连接
        Connection conn = THREAD_LOCAL.get();
        //若未获取到连接
        if (conn == null) {
            //连接数小于初始的情况
            if (connection < config.getInit()) {
                synchronized (ConnectPool.class) {
                    //从初始连接池中获取连接并添加到threadLocal中
                    connection++;
                    conn = arr.removeFirst();
                    THREAD_LOCAL.set(conn);
                    return conn;
                }
            }
            //连接数大于初始的情况
            else if (connection >= config.getInit() && connection < config.getMax()) {
                synchronized (ConnectPool.class) {
                    //创建一个新的连接并添加到threadLocal中
                    connection++;
                    conn = Jdbc.getConnection();
                    THREAD_LOCAL.set(conn);
                    System.out.println("--------------------------");
                    return conn;
                }
            }

            //连接数大于最大值的情况
            else {
                System.out.println("连接过多,当前连接数" + connection);
                return null;
            }
        } else {
            return conn;
        }
    }

    /**
     * 通过连接池底层获取连接,以实现等待重连
     *
     * @return Connection连接
     */
    @Override
    public Connection getConnection() throws InterruptedException, SQLException {
        Connection conn = null;
        int count = 1;
        //通过连接池底层获取连接
        conn = this.getConnectionInner();

        while (conn == null) {
            //等待时间后进行重连
            System.out.println("重连次数:" + count);
            Thread.sleep(config.getWaitTime());
            conn = this.getConnectionInner();
            count++;
        }
        //重新连接完成后返回conn
        return conn;
    }

    /**
     * 归还连接到连接池
     */
    @Override
    public void returnConnection() throws SQLException {
        //获取threadLocal连接
        Connection conn = THREAD_LOCAL.get();
        THREAD_LOCAL.remove();
        connection--;
        if (conn != null) {
            //移除连接
            if (!conn.isClosed()) {
                //将连接的自动提交打开
                conn.setAutoCommit(true);
                arr.add(conn);
            }
        }
        releaseConnection();
    }

    /**
     * 释放多余的链接
     */
    @Override
    public void releaseConnection() {
        while (arr.size() > config.getInit()) {
            Connection conn = arr.remove(config.getInit());
            try {
                conn.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
            System.out.println("成功释放资源");
        }

    }

    /**
     * 释放资源
     */
    @Override
    public void releaseAll(Connection conn, Statement state, ResultSet resultSet) {
        Jdbc.releaseAll(conn, state, resultSet);

    }


}
